package com.example.usbfileutils

import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbManager
import android.util.Log
import com.example.usbfileutils.bylibaums.FileCopyExecutors
import me.jahnen.libaums.core.UsbMassStorageDevice
import me.jahnen.libaums.core.fs.FileSystem
import me.jahnen.libaums.core.fs.UsbFile
import me.jahnen.libaums.core.fs.UsbFileStreamFactory.createBufferedOutputStream
import me.jahnen.libaums.core.partition.Partition
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.io.OutputStream


class USBFileManagerLibaums private constructor() {

    private lateinit var mContext: Context
    private lateinit var usbManager: UsbManager
    private var storageDevices: Array<UsbMassStorageDevice>? = null
    private var currentDevice: UsbMassStorageDevice? = null
    private var rootFilePath: UsbFile? = null
    private var currentFs: FileSystem? = null
    private lateinit var pendingIntent: PendingIntent
    private val fileCopyExecutors: FileCopyExecutors = FileCopyExecutors()

    private val destFilePath = "RaceExportData"

    companion object {
        private val TAG = "USBFileManager"
        private const val ACTION_USB_PERMISSION: String =
            "com.android.usbmanager.permission.USB_PERMISSION"
        val instance = USBFileManagerLibaums()
    }

    private fun registerBroadCastReceiver() {
        val filter = IntentFilter()
        filter.addAction(ACTION_USB_PERMISSION)
        filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED)
        filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
        mContext.registerReceiver(mOtgReceiver, filter)
    }

    fun unRegisterUDiskReceiver() {
        mContext.unregisterReceiver(mOtgReceiver)
    }

    private val mOtgReceiver = object : android.content.BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent?.action) {
                ACTION_USB_PERMISSION -> {
                    //用户授权
                    Log.i(TAG, "User Authorization")

                    storageDevices?.get(0)?.let { readDeviceInfo(it) }
                }

                UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
                    //插入U盘
                    Log.i(TAG, "Insert USB Device ----")
                    findAvaliableDevice()
                }

                UsbManager.ACTION_USB_DEVICE_DETACHED -> {
                    //拔出U盘
                    Log.i(TAG, "Disconnect Usb Devices ---")
                    reset()
                }
            }
        }

    }

    fun reset() {
        storageDevices = null
        currentDevice = null
        rootFilePath = null
    }

    fun init(context: Context) {
        mContext = context.applicationContext

        usbManager = mContext.getSystemService(Context.USB_SERVICE) as UsbManager

        pendingIntent = PendingIntent.getBroadcast(
            mContext, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE
        )

        registerBroadCastReceiver()
        findAvaliableDevice()
    }

    private fun findAvaliableDevice() {

        storageDevices = UsbMassStorageDevice.getMassStorageDevices(mContext);

        Log.i(TAG, "find usb devices size ${storageDevices?.size}")

        storageDevices?.takeIf { it.isNotEmpty() }?.let {

            currentDevice = it[0]

            if (usbManager.hasPermission(currentDevice?.usbDevice)) {
                Log.i(
                    TAG, "Has permission, start to read the device"
                )
                readDeviceInfo(currentDevice!!)
            } else {
                Log.i(
                    TAG, "Dont't have permission, start to request permission"
                )
                usbManager.requestPermission(currentDevice?.usbDevice, pendingIntent)
            }
        }
    }

    private fun readDeviceInfo(device: UsbMassStorageDevice) {

        device.init() //初始化

        //设备分区
        device.partitions.takeIf { it.isNotEmpty() }.let {
            val partition: Partition = device.partitions[1]
            //文件系统
            currentFs = partition.fileSystem

            currentFs?.let {
                Log.i(
                    TAG,
                    "Read Disk Info====:" + it.capacity + "  " + it.occupiedSpace + " " + it.freeSpace + " " + it.chunkSize
                )
                rootFilePath = it.rootDirectory
                rootFilePath?.listFiles()?.forEach { file ->
                    Log.i(
                        TAG,
                        "${file.name}--${if (file.isDirectory) "Directory" else file.length}"
                    )
                }
            }

        }
    }

    fun copyFilesToUSB(srcFilePath: File) {

        if (rootFilePath == null) {
            Log.e(TAG, "root file path is null")
            return
        }

        rootFilePath?.let {
            copyFiles(srcFilePath, it)
        }

        fileCopyExecutors.start()
    }

    private fun copyFiles(srcFilePath: File, currentUsbDir: UsbFile) {

        if (srcFilePath.isDirectory) {

            var destDir: UsbFile? = null

            try {
                Log.d(TAG, "is a directory,create")
                destDir = currentUsbDir.createDirectory(srcFilePath.name)
            } catch (e: IOException) {
                e.printStackTrace()
            }

            destDir?.let { destDirPath ->
                var listFiles = srcFilePath.listFiles()

                Log.d(TAG, "$srcFilePath has file length ${listFiles?.size}")

                listFiles?.forEach {
                    copyFiles(it, destDirPath)
                }
            }

        } else {
            Log.d(TAG, "copy $srcFilePath to the Usb device")
//            fileCopyExecutors.addTask(FileCopyTask(srcFilePath, currentUsbDir, currentFs!!))
            copyFile(srcFilePath, currentUsbDir)

        }
    }

    private fun copyFile(file: File, currentUsbDir: UsbFile) {
        try {
            val usbFile = currentUsbDir.createFile(file.name)
//            try {
//                usbFile.delete()
//            } catch (e: IOException) {
//                e.printStackTrace()
//            }

            val size = file.length()
            usbFile.length = file.length()

            val inputStream = FileInputStream(file)
            val outputStream: OutputStream = createBufferedOutputStream(usbFile, currentFs!!)
            val bytes = ByteArray(1337)
            var count: Int
            var total: Long = 0
            while (inputStream!!.read(bytes).also { count = it } != -1) {
                outputStream.write(bytes, 0, count)
                if (size > 0) {
                    total += count.toLong()
                    var progress = total.toInt()
                    if (file.length() > Int.MAX_VALUE) {
                        progress = (total / 1024).toInt()
                    }

//                    Log.d(TAG, "copy file : $progress")
                }

            }
            outputStream.close()
            inputStream.close()

            Log.d(TAG, "copy file ${file.name} to ${usbFile.absolutePath} successfully")

        } catch (e: IOException) {
            Log.e(TAG, "error copying! ${file.absolutePath}", e)
        }
    }

    fun destroy() {
        fileCopyExecutors.stop()
        unRegisterUDiskReceiver()
    }
}